home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / Libraries / CW GUSI 1.6.4 / src / GUSIPPC.cp < prev    next >
Text File  |  1995-11-05  |  17KB  |  854 lines

  1. /*********************************************************************
  2. Project    :    GUSI                -    Grand Unified Socket Interface
  3. File        :    GUSIPPC.cp        -    PPC Sockets
  4. Author    :    Matthias Neeracher
  5. Language    :    MPW C/C++
  6.  
  7. $Log: GUSIPPC.cp,v $
  8. Revision 1.4  1994/12/30  20:14:30  neeri
  9. Wake up process from completion procedure.
  10.  
  11. Revision 1.3  1994/08/10  00:06:01  neeri
  12. Sanitized for universal headers.
  13.  
  14. Revision 1.2  1994/05/01  23:30:32  neeri
  15. Enable recvfrom with non-NULL from address.
  16.  
  17. Revision 1.1  1994/02/25  02:30:02  neeri
  18. Initial revision
  19.  
  20. Revision 0.13  1993/12/30  00:00:00  neeri
  21. Fiddle with select()
  22.  
  23. Revision 0.12  1993/09/01  00:00:00  neeri
  24. Throw out nonbreaking spaces
  25.  
  26. Revision 0.11  1993/06/20  00:00:00  neeri
  27. Changed sa_constr_ppc
  28.  
  29. Revision 0.10  1993/02/07  00:00:00  neeri
  30. New configuration technique
  31.  
  32. Revision 0.9  1992/12/17  00:00:00  neeri
  33. Forgot to clear errno in PPCSocketDomain::socket()
  34.  
  35. Revision 0.8  1992/12/06  00:00:00  neeri
  36. Check flags
  37.  
  38. Revision 0.7  1992/09/13  00:00:00  neeri
  39. Always complete write
  40.  
  41. Revision 0.6  1992/09/07  00:00:00  neeri
  42. Implement ioctl()
  43.  
  44. Revision 0.5  1992/08/30  00:00:00  neeri
  45. Move hasPPC here
  46.  
  47. Revision 0.4  1992/08/10  00:00:00  neeri
  48. Correct select()
  49.  
  50. Revision 0.3  1992/08/03  00:00:00  neeri
  51. Introduce additional buffering
  52.  
  53. Revision 0.2  1992/08/03  00:00:00  neeri
  54. Approximately correct, except for sync/async
  55.  
  56. Revision 0.1  1992/08/02  00:00:00  neeri
  57. Put some further work in
  58.  
  59. *********************************************************************/
  60.  
  61. #include "GUSIPPC_P.h"
  62.  
  63. #include <Errors.h>
  64. #include <ADSP.h>
  65. #include <Devices.h>
  66. #include <GestaltEqu.h>
  67. #include <PLStringFuncs.h>
  68. #include <LowMem.h>
  69.  
  70. class PPCSocket;                             // That's what this file's all about
  71.  
  72. struct PPCPB {
  73.     PPCParamBlockRec    ppc;
  74.     PPCSocket *            sock;
  75. };
  76.  
  77. class PPCSocket : public Socket    {        
  78.     friend class PPCSocketDomain;    
  79.     friend pascal void PPCReadHellHound(PPCPB * pb);
  80.     friend pascal void PPCWriteHellHound(PPCPB * pb);
  81.  
  82.     enum {
  83.         notBound, 
  84.         notOpen,
  85.         isListening,
  86.         isOpen,
  87.         isAccepted}        status;
  88.     Boolean                nonblocking;
  89.     Boolean                readPending;
  90.     Boolean                writePending;
  91.     Boolean                readShutDown;
  92.     Boolean                writeShutDown;
  93.     LocationNameRec    location;
  94.     PPCPortRec            port;
  95.     LocationNameRec    peerLoc;
  96.     PPCPortRec            peerPort;
  97.     PPCPB                    pb;
  98.     PPCPB    *                rpb;
  99.     RingBuffer *        rb;
  100.     RingBuffer *        wb;
  101.  
  102. #if !GENERATINGCFM
  103.     Ptr                        processA5;    /* Our A5 world */
  104. #endif    
  105.     
  106.                     PPCSocket();
  107.                     PPCSocket(const PPCSocket & acceptFrom);
  108.                     
  109.     virtual         ~PPCSocket();
  110.     
  111.     int            Alloc();
  112.     void            HellHoundsOnMyTrail();
  113. public:
  114.     void            Ready();
  115.  
  116.     virtual int    bind(void * name, int namelen);
  117.     virtual int getsockname(void * name, int * namelen);
  118.     virtual int getpeername(void *name, int *namelen);
  119.     virtual int    fcntl(unsigned int cmd, int arg);
  120.     virtual int listen(int qlen);
  121.     virtual int connect(void * address, int addrlen);
  122.     virtual Socket * accept(void * address, int * addrlen);
  123.     virtual int recvfrom(void * buffer, int buflen, int flags, void * from, int * fromlen);
  124.     virtual int sendto(void * buffer, int buflen, int flags, void * to, int tolen);
  125.     virtual int shutdown(int how);
  126.     virtual int select(Boolean * canRead, Boolean * canWrite, Boolean * exception);
  127.     virtual int    ioctl(unsigned int request, void *argp);
  128. };    
  129.  
  130. PPCSocketDomain    PPCSockets;
  131.  
  132. #if GENERATINGCFM
  133. inline void PPCSocket::Ready() 
  134. {
  135.     PPCSockets.Ready();
  136. }
  137. #endif    
  138.  
  139. /************************ PPC Toolbox initialization ************************/
  140.  
  141. pascal OSErr PPCInit_P()
  142. {
  143.     OSErr        err;
  144.     long        attr;
  145.         
  146.     if (err = Gestalt(gestaltPPCToolboxAttr, &attr))
  147.         return err;
  148.         
  149.     if (!(attr & gestaltPPCSupportsRealTime))
  150.         err = PPCInit();
  151.  
  152.     return err;
  153. }
  154.  
  155. Feature hasPPC(PPCInit_P);
  156.  
  157. /********************* Link stuffing procedures *********************/
  158.  
  159. #if !GENERATINGCFM
  160.  
  161. void PPCSocket::Ready() 
  162. {
  163.     long saveA5 = SetA5(long(processA5));
  164.     
  165.     PPCSockets.Ready();
  166.     
  167.     SetA5(saveA5);
  168. }
  169.  
  170. #endif    
  171.  
  172. #if GENERATINGCFM
  173. RoutineDescriptor    uPPCReadHellHound = 
  174.         BUILD_ROUTINE_DESCRIPTOR(uppPPCCompProcInfo, PPCReadHellHound);
  175. #else
  176. #define uPPCReadHellHound PPCReadHellHound
  177. #endif
  178.  
  179. pascal void PPCReadHellHound(PPCPB * pb)
  180. {
  181.     if (!pb->sock->rb)                                    // We're closing
  182.         return;
  183.         
  184.     RingBuffer &     buf     =    *pb->sock->rb;
  185.     PPCReadPBRec & p         =    pb->ppc.readParam;
  186.     Boolean &        pend    =    pb->sock->readPending;
  187.     
  188.     if (buf.Locked())
  189.         buf.Later(Deferred(PPCReadHellHound), pb);
  190.     else    {
  191.         pb->sock->Ready();
  192.         
  193.         buf.Later(nil, nil);
  194.         if (pend) {
  195.             pend    =    false;
  196.             
  197.             if (p.ioResult)    {
  198.                 pb->sock->readShutDown    =    true;
  199.                 
  200.                 return;
  201.             }
  202.             
  203.             buf.Validate(p.actualLength);
  204.         }
  205.         
  206.         if (!buf.Free()) 
  207.             buf.Later(Deferred(PPCReadHellHound), pb);
  208.         else {
  209.             long    max    =    1000000;
  210.             
  211.             p.ioCompletion    =    PPCCompUPP(&uPPCReadHellHound);
  212.             p.bufferPtr        =    buf.Producer(max);
  213.             p.bufferLength    =    max;
  214.             pend                =    true;
  215.             
  216.             PPCReadAsync(&p);
  217.         }
  218.     }
  219. }
  220.  
  221. #if GENERATINGCFM
  222. RoutineDescriptor    uPPCWriteHellHound = 
  223.         BUILD_ROUTINE_DESCRIPTOR(uppPPCCompProcInfo, PPCWriteHellHound);
  224. #else
  225. #define uPPCWriteHellHound PPCWriteHellHound
  226. #endif
  227.  
  228. pascal void PPCWriteHellHound(PPCPB * pb)
  229. {
  230.     if (!pb->sock->wb)                                    // We're closing
  231.         return;
  232.         
  233.     RingBuffer &      buf     =    *pb->sock->wb;
  234.     PPCWritePBRec & p         =    pb->ppc.writeParam;
  235.     Boolean &         pend    =    pb->sock->writePending;
  236.     
  237.     if (buf.Locked())
  238.         buf.Later(Deferred(PPCWriteHellHound), pb);
  239.     else    {
  240.         pb->sock->Ready();
  241.         
  242.         buf.Later(nil, nil);
  243.         
  244.         if (pend) {
  245.             pend    =    false;
  246.             
  247.             if (p.ioResult)    {
  248.                 pb->sock->writeShutDown    =    true;
  249.                 
  250.                 return;
  251.             }
  252.  
  253.             buf.Invalidate(p.actualLength);
  254.         }
  255.         
  256.         if (!buf.Valid()) 
  257.             buf.Later(Deferred(PPCWriteHellHound), pb);
  258.         else {
  259.             long    max    =    1000000;
  260.             
  261.             p.ioCompletion    =    PPCCompUPP(&uPPCWriteHellHound);
  262.             p.bufferPtr        =    buf.Consumer(max);
  263.             p.bufferLength    =    max;
  264.             p.more            =    false;
  265.             p.userData        =    0;
  266.             p.blockCreator    =    'GU∑I';
  267.             p.blockType        =    'GU∑I';
  268.             pend                =    true;
  269.             
  270.             PPCWriteAsync(&p);
  271.         }
  272.     }
  273. }
  274.  
  275. /************************ PPCSocket members ************************/
  276.  
  277. PPCSocket::PPCSocket()
  278. {
  279.     status            =    PPCSocket::notBound;
  280.     nonblocking        =    false;
  281.     pb.sock            =    this;
  282.     rpb                =    nil;
  283.     rb                    =    nil;
  284.     wb                    =    nil;
  285.     readPending        =    false;
  286.     writePending    =    false;
  287.     readShutDown    =    false;
  288.     writeShutDown    =    false;
  289.  
  290. #if !GENERATINGCFM
  291.     processA5        = LMGetCurrentA5();
  292. #endif    
  293. }
  294.  
  295. PPCSocket::PPCSocket(const PPCSocket & acceptFrom)
  296. {
  297.     status            =    PPCSocket::isAccepted;
  298.     nonblocking        =    acceptFrom.nonblocking;
  299.     pb.ppc            =    acceptFrom.pb.ppc;
  300.     pb.sock            =    this;
  301.     rpb                =    nil;
  302.     rb                    =    nil;
  303.     wb                    =    nil;
  304.     readPending        =    false;
  305.     writePending    =    false;
  306.     readShutDown    =    false;
  307.     writeShutDown    =    false;
  308.     location            =    acceptFrom.location;
  309.     port                =    acceptFrom.port;
  310.     peerLoc            =    acceptFrom.peerLoc;
  311.     peerPort            =    acceptFrom.peerPort;
  312.  
  313. #if !GENERATINGCFM
  314.     processA5        = LMGetCurrentA5();
  315. #endif    
  316. }
  317.  
  318. PPCSocket::~PPCSocket()
  319. {
  320.     if (rb)    {
  321.         delete rb;
  322.         
  323.         rb = nil;
  324.     }
  325.     
  326.     if (wb)    {
  327.         delete wb;
  328.         
  329.         wb = nil;
  330.     }
  331.  
  332.     switch (status) {
  333.     case PPCSocket::isAccepted:
  334.         PPCEndSync(&pb.ppc.endParam);
  335.         
  336.         break;                                        // Don't close the port
  337.     case PPCSocket::isListening:
  338.     case PPCSocket::isOpen:
  339.         PPCEndSync(&pb.ppc.endParam);
  340.  
  341.         /* Fall through */
  342.     case PPCSocket::notOpen:
  343.         PPCCloseSync(&pb.ppc.closeParam);
  344.         /* Fall through */
  345.     case PPCSocket::notBound:
  346.         break;
  347.     }
  348. }
  349.  
  350. int PPCSocket::Alloc()
  351. {
  352.     if (!rpb)
  353.         rpb    =    new PPCPB;
  354.     
  355.     if (!rpb)
  356.         goto error;
  357.     
  358.     rpb->sock    =    this;
  359.     
  360.     if (!rb)
  361.         rb    =    new RingBuffer(2048);
  362.     
  363.     if (!rb)    
  364.         goto error;
  365.     if (!*rb)
  366.         goto errRB;
  367.     
  368.     if (!wb)
  369.         wb =    new RingBuffer(2048);
  370.     
  371.     if (!wb)    
  372.         goto errRB;
  373.     if (!*wb)
  374.         goto errWB;
  375.     
  376.     return 0;
  377.  
  378. errWB:
  379.     delete wb;
  380.     
  381.     wb    =    nil;
  382. errRB:
  383.     delete rb;
  384.     
  385.     rb    =    nil;
  386. error:
  387.     return GUSI_error(ENOMEM);
  388. }
  389.  
  390. void PPCSocket::HellHoundsOnMyTrail()
  391. {
  392.     rpb->ppc.readParam.sessRefNum        =    pb.ppc.startParam.sessRefNum;
  393.     
  394.     PPCReadHellHound(rpb);
  395.     PPCWriteHellHound(&pb);
  396. }
  397.  
  398. int PPCSocket::fcntl(unsigned int cmd, int arg)
  399. {
  400.     switch (cmd)    {
  401.     case F_GETFL:
  402.         if (nonblocking)
  403.             return FNDELAY;
  404.         else
  405.             return 0;
  406.     case F_SETFL:
  407.         if (arg & FNDELAY)
  408.             nonblocking = true;
  409.         else
  410.             nonblocking = false;
  411.             
  412.         return 0;
  413.     default:
  414.         return GUSI_error(EOPNOTSUPP);
  415.     }
  416. }
  417.  
  418. int PPCSocket::ioctl(unsigned int request, void *argp)
  419. {
  420.     switch (request)    {
  421.     case FIONBIO:
  422.         nonblocking    =    (Boolean) *(long *) argp;
  423.         
  424.         return 0;
  425.     case FIONREAD:
  426.         switch(status)    {
  427.         case PPCSocket::isAccepted:
  428.         case PPCSocket::isOpen:
  429.             break;
  430.         default:
  431.             return GUSI_error(ENOTCONN);    
  432.         }
  433.     
  434.         *(unsigned long *) argp    = rb->Valid();
  435.         
  436.         return 0;
  437.     default:
  438.         return GUSI_error(EOPNOTSUPP);
  439.     }
  440. }
  441.  
  442. int PPCSocket::bind(void *sa_name, int)
  443. {
  444.     struct sockaddr_ppc *    addr = (struct sockaddr_ppc *) sa_name;
  445.     
  446.     if (addr->family != AF_PPC)
  447.         GUSI_error(EAFNOSUPPORT);
  448.         
  449.     if (status != PPCSocket::notBound)
  450.         return GUSI_error(EINVAL);
  451.     
  452.     location = addr->location;
  453.     port        = addr->port;
  454.     
  455.     pb.ppc.openParam.ioCompletion        =    nil;
  456.     pb.ppc.openParam.serviceType        =    ppcServiceRealTime;
  457.     pb.ppc.openParam.resFlag            =    0;
  458.     pb.ppc.openParam.portName            =    &port;
  459.     pb.ppc.openParam.locationName        =    &location;
  460.     pb.ppc.openParam.networkVisible    =    true;
  461.     
  462.     switch (PPCOpenSync(&pb.ppc.openParam))    {
  463.     case noErr:
  464.         break;
  465.     case nameTypeErr:
  466.     case badReqErr:
  467.     case badPortNameErr:
  468.     case badLocNameErr:
  469.         return GUSI_error(EINVAL);
  470.     case noGlobalsErr:
  471.         return GUSI_error(ENOMEM);
  472.     case portNameExistsErr:
  473.     case nbpDuplicate:
  474.         return GUSI_error(EADDRINUSE);
  475.     default:
  476.         return GUSI_error(EINVAL);
  477.     }
  478.     
  479.     status =    PPCSocket::notOpen;
  480.     
  481.     return 0;
  482. }
  483.  
  484. int PPCSocket::getsockname(void *name, int *namelen)
  485. {
  486.     struct sockaddr_ppc    addr;
  487.     
  488.     addr.family            =    AF_PPC;
  489.     addr.location        =    location;
  490.     addr.port            =    port;
  491.     
  492.     memcpy(name, &addr, *namelen = min(*namelen, int(sizeof(struct sockaddr_ppc))));
  493.     
  494.     return 0;
  495. }
  496.  
  497. int PPCSocket::getpeername(void *name, int *namelen)
  498. {
  499.     struct sockaddr_ppc    addr;
  500.     
  501.     addr.family            =    AF_PPC;
  502.     addr.location        =    peerLoc;
  503.     addr.port            =    peerPort;
  504.     
  505.     memcpy(name, &addr, *namelen = min(*namelen, int(sizeof(struct sockaddr_ppc))));
  506.     
  507.     return 0;
  508. }
  509.  
  510. int PPCSocket::listen(int)
  511. {    
  512.     switch (status)    {
  513.     case PPCSocket::notBound:
  514.         return GUSI_error(EINVAL);
  515.     case PPCSocket::isOpen:
  516.     case PPCSocket::isListening:
  517.         return GUSI_error(EISCONN);
  518.     default:
  519.         break;
  520.     }
  521.     
  522.     pb.ppc.informParam.autoAccept        =    true;
  523.     pb.ppc.informParam.portName            = &peerPort;
  524.     pb.ppc.informParam.locationName     = &peerLoc;
  525.     pb.ppc.informParam.userName            =    nil;
  526.     
  527.     if (PPCInformAsync(&pb.ppc.informParam))
  528.         return GUSI_error(EINVAL);
  529.         
  530.     status = PPCSocket::isListening;
  531.     
  532.     return 0;
  533. }
  534.  
  535. int PPCSocket::connect(void *sa_name, int)
  536. {
  537.     Boolean                         guest;
  538.     struct sockaddr_ppc *    addr = (struct sockaddr_ppc *) sa_name;
  539.     Str32                            uname;
  540.     
  541.     switch (status)    {
  542.     case PPCSocket::notBound:
  543.         return GUSI_error(EINVAL);
  544.     case PPCSocket::isOpen:
  545.     case PPCSocket::isListening:
  546.     case PPCSocket::isAccepted:
  547.         return GUSI_error(EISCONN);
  548.     default:
  549.         break;
  550.     }
  551.     
  552.     if (Alloc())
  553.         return -1;
  554.  
  555.     if (addr->family != AF_PPC)
  556.         GUSI_error(EAFNOSUPPORT);
  557.     
  558.     peerLoc    = addr->location;
  559.     peerPort    = addr->port;
  560.     uname[0] = 0;
  561.         
  562.     pb.ppc.startParam.serviceType        =    ppcServiceRealTime;
  563.     pb.ppc.startParam.resFlag            =    0;
  564.     pb.ppc.startParam.portName            = &peerPort;
  565.     pb.ppc.startParam.locationName     = &peerLoc;
  566.     pb.ppc.startParam.userData            =    0;
  567.     
  568.     if (StartSecureSession(&pb.ppc.startParam, uname, true, true, &guest, (StringPtr) "\p"))
  569.         return GUSI_error(EINVAL);
  570.         
  571.     status                                     =     PPCSocket::isOpen;
  572.     
  573.     HellHoundsOnMyTrail();
  574.     
  575.     return 0;
  576. }
  577.  
  578. Socket * PPCSocket::accept(void * address, int * addrlen)
  579. {
  580.     PPCSocket    *    newsock;
  581.     
  582.     if (status != PPCSocket::isListening)
  583.         return (Socket *) GUSI_error_nil(ENOTCONN);
  584.  
  585.     if (nonblocking && pb.ppc.informParam.ioResult == 1)
  586.         return (Socket *) GUSI_error_nil(EWOULDBLOCK);
  587.         
  588.     SPINP(pb.ppc.informParam.ioResult == 1, SP_MISC, 0);
  589.  
  590.     if (pb.ppc.informParam.ioResult)
  591.         return (Socket *) GUSI_error_nil(EINVAL);
  592.     
  593.     newsock    =    new PPCSocket(*this);
  594.  
  595.     if (!newsock)
  596.         return (Socket *) GUSI_error_nil(ENOMEM);
  597.         
  598.     if (newsock->Alloc())    {
  599.         delete newsock;
  600.         
  601.         return (Socket *) GUSI_error_nil(ENOMEM);
  602.     }
  603.     
  604.     newsock->HellHoundsOnMyTrail();
  605.                                                     
  606.     if (address && addrlen)
  607.         getpeername(address, addrlen);
  608.  
  609.     pb.ppc.informParam.autoAccept        =    true;
  610.     pb.ppc.informParam.portName        = &peerPort;
  611.     pb.ppc.informParam.locationName     = &peerLoc;
  612.     pb.ppc.informParam.userName        =    nil;
  613.     
  614.     PPCInformAsync(&pb.ppc.informParam);
  615.         
  616.     return newsock;
  617. }
  618.  
  619. int PPCSocket::recvfrom(void * buffer, int buflen, int flags, void * from, int * fromlen)
  620. {
  621.     long    len    =    buflen;
  622.     
  623.     if (from)
  624.         getpeername(from, fromlen);
  625.     if (flags)
  626.         return GUSI_error(EOPNOTSUPP);
  627.     
  628.     switch(status)    {
  629.     case PPCSocket::isAccepted:
  630.     case PPCSocket::isOpen:
  631.         break;
  632.     default:
  633.         return GUSI_error(ENOTCONN);    
  634.     }
  635.     
  636.     if (!rb->Valid())    
  637.         if (readShutDown)
  638.             return 0;
  639.         else if (nonblocking)
  640.             return GUSI_error(EWOULDBLOCK);
  641.         else
  642.             SPIN(!rb->Valid(), SP_STREAM_READ, 0);
  643.     
  644.     rb->Consume(Ptr(buffer), len);
  645.     
  646.     return len;
  647. }
  648.  
  649. int PPCSocket::sendto(void * buffer, int buflen, int flags, void * to, int)
  650. {
  651.     long    len    =    buflen;
  652.     long    done    =    0;
  653.     
  654.     if (to)
  655.         return GUSI_error(EOPNOTSUPP);
  656.     if (flags)
  657.         return GUSI_error(EOPNOTSUPP);
  658.     
  659.     switch(status)    {
  660.     case PPCSocket::isAccepted:
  661.     case PPCSocket::isOpen:
  662.         break;
  663.     default:
  664.         return GUSI_error(ENOTCONN);    
  665.     }
  666.     
  667.     if (writeShutDown)
  668.         return GUSI_error(ESHUTDOWN);
  669.     
  670.     if (!wb->Free())
  671.         if (nonblocking)
  672.             return GUSI_error(EWOULDBLOCK);
  673.         
  674.     for (;;) {
  675.         wb->Produce(Ptr(buffer), len);
  676.         
  677.         done        +=    len;
  678.         
  679.         if (nonblocking)
  680.             break;
  681.         
  682.         buflen    -=    int(len);
  683.         
  684.         if (!buflen)
  685.             break;
  686.         
  687.         buffer     =    Ptr(buffer) + len;
  688.         len        =    buflen;
  689.         
  690.         SPIN(!wb->Free(), SP_STREAM_WRITE, 0);
  691.     }
  692.     
  693.     return done;
  694. }
  695.  
  696. int PPCSocket::shutdown(int how)
  697. {
  698.     if (how < 0 || how > 2)
  699.         return GUSI_error(EINVAL);
  700.     
  701.     if (how)
  702.         writeShutDown    =    true;
  703.     if (!(how & 1))
  704.         readShutDown    =    true;
  705.         
  706.     return 0;
  707. }
  708.  
  709. int PPCSocket::select(Boolean * canRead, Boolean * canWrite, Boolean *)
  710. {
  711.     int    goodies     =     0;
  712.     
  713.     if (canRead)
  714.         switch (status) {
  715.         case PPCSocket::isListening:
  716.             if (pb.ppc.informParam.ioResult != 1) {
  717.                 *canRead =     true;
  718.                 ++goodies;
  719.             }
  720.             break;
  721.         case PPCSocket::isAccepted:
  722.         case PPCSocket::isOpen:
  723.             if (rb->Valid() || readShutDown) {
  724.                 *canRead =     true;
  725.                 ++goodies;
  726.             } 
  727.             break;
  728.         default:
  729.             *canRead =     true;
  730.             ++goodies;
  731.             break;
  732.         }
  733.     
  734.     if (canWrite)
  735.         switch (status) {
  736.         case PPCSocket::isAccepted:
  737.         case PPCSocket::isOpen:
  738.             if (wb->Free()) {
  739.                 *canWrite = true;
  740.                 ++goodies;
  741.             }
  742.             break;
  743.         default:
  744.             *canWrite = true;
  745.             ++goodies;
  746.             break;
  747.         }
  748.     
  749.     return goodies;
  750. }
  751.  
  752. /********************* PPCSocketDomain member **********************/
  753.  
  754. extern "C" void GUSIwithPPCSockets()
  755. {
  756.     PPCSockets.DontStrip();
  757. }
  758.  
  759. PPCSocketDomain::PPCSocketDomain()
  760.     :    SocketDomain(AF_PPC)    
  761. {
  762. }
  763.  
  764. Socket * PPCSocketDomain::socket(int type, short)
  765. {
  766.     PPCSocket * sock    =    nil;
  767.     
  768.     errno = 0;
  769.     
  770.     if (!hasPPC)
  771.         GUSI_error(EOPNOTSUPP);
  772.     else 
  773.         switch (type)    {
  774.         case SOCK_STREAM:
  775.             sock = new PPCSocket();
  776.             break;
  777.         default:
  778.             GUSI_error(ESOCKTNOSUPPORT);
  779.         }    
  780.     
  781.     if (sock && errno)    {
  782.         delete sock;
  783.         
  784.         return nil;
  785.     } else
  786.         return sock;
  787. }
  788.  
  789. static sa_constr_ppc *    CurConstr;
  790.  
  791. static pascal Boolean GUSIBrowseFilter(LocationNamePtr, PortInfoPtr port)
  792. {
  793.     if (CurConstr->flags & PPC_CON_MATCH_NAME)
  794.         if (PLstrcmp(port->name.name, CurConstr->match.name))
  795.             return false;
  796.     if (CurConstr->flags & PPC_CON_MATCH_TYPE)
  797.         if (port->name.portKindSelector != ppcByString || PLstrcmp(port->name.u.portTypeStr, CurConstr->match.u.portTypeStr))
  798.             return false;
  799.     
  800.     return true;
  801. }
  802.  
  803. #if GENERATINGCFM
  804. RoutineDescriptor    uGUSIBrowseFilter = 
  805.         BUILD_ROUTINE_DESCRIPTOR(uppPPCFilterProcInfo, GUSIBrowseFilter);
  806. #else
  807. #define uGUSIBrowseFilter GUSIBrowseFilter
  808. #endif
  809.  
  810. int PPCSocketDomain::choose(int, char * prompt, void * constraint, int flags, void * name, int * namelen)
  811. {
  812.     sockaddr_ppc            addr;
  813.     Str255                    promp;
  814.     StringPtr                nbp    = nil;
  815.     PortInfoRec                info;
  816.     static sa_constr_ppc constr;
  817.     
  818.     if (flags & (CHOOSE_NEW | CHOOSE_DIR))
  819.         return GUSI_error(EINVAL);
  820.     
  821.     CopyC2PStr(prompt, promp);    
  822.     CurConstr=    (sa_constr_ppc *) constraint;
  823.     
  824.     if (!CurConstr || !(CurConstr->flags & PPC_CON_NEWSTYLE)) {
  825.         if (CurConstr && ((char *) constraint)[0]) {
  826.             constr.flags    =    PPC_CON_NEWSTYLE + PPC_CON_MATCH_NBP;
  827.             nbp                =    StringPtr(constraint);
  828.         } else
  829.             constr.flags     =    PPC_CON_NEWSTYLE;
  830.         
  831.         CurConstr    =    &constr;
  832.     } else if (CurConstr->flags & PPC_CON_MATCH_NBP)
  833.         nbp = CurConstr->nbpType;
  834.     
  835.     if (
  836.         PPCBrowser(
  837.             promp, 
  838.             (StringPtr) "\p", 
  839.             false, 
  840.             &addr.location, 
  841.             &info, 
  842.             (CurConstr->flags & (PPC_CON_MATCH_NAME | PPC_CON_MATCH_TYPE)) ? PPCFilterUPP(&uGUSIBrowseFilter) : PPCFilterUPP(nil),
  843.             nbp ? nbp : (StringPtr) "\pPPCToolBox")
  844.     )
  845.         return GUSI_error(EINTR);
  846.  
  847.     addr.family    =    AF_PPC;
  848.     addr.port    =    info.name;
  849.     
  850.     memcpy(name, &addr, *namelen = min(*namelen, int(sizeof(sockaddr_ppc))));
  851.     
  852.     return 0;
  853. }
  854.